package com.insideClass.AnonymityInsideClass;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

interface Combiner<T>{
    T combine(T x,T y);
}
interface UnaryFunction<R,T>{
    R function(T x);
}
interface Collector<T> extends UnaryFunction<T,T>{
    T result();
}
interface UnaryPredicate<T>{
    boolean test(T x);
}
/**
 * @author 13699
 */
public class Functional {
    public static<T> T
    reduce(Iterable<T> seq,Combiner<T> combiner){
        Iterator<T> it=seq.iterator();
        if(it.hasNext()){
            T result=it.next();
            while (it.hasNext()){
                result=combiner.combine(result,it.next());
            }
            return result;
        }
        return null;
    }
    public static<T> Collector<T>
    forEach(Iterator<T> seq,Collector<T> func){
        for (Iterator<T> it = seq; it.hasNext(); ) {
            T t = it.next();
            func.function(t);
        }
        return func;
    }
    public static <R,T> List<R>
    transform(Iterator<T> seq,UnaryFunction<R,T> func){
        List<R> result=new ArrayList<>();
        for (Iterator<T> it = seq; it.hasNext(); ) {
            T t = it.next();
            result.add(func.function(t));
        }
        return result;
    }
    public static <T> List<T> filter(Iterator<T> seq,UnaryPredicate<T> pred){
        List<T> result=new ArrayList<>();
        for (Iterator<T> it = seq; it.hasNext(); ) {
            T t = it.next();
            if(pred.test(t)){
                result.add(t);
            }
        }
        return result;
    }
    static class IntegerAdder implements Combiner<Integer>{

        @Override
        public Integer combine(Integer x, Integer y) {
            return x+y;
        }
    }
    static class IntegerSubtracter implements Combiner<Integer>{

        @Override
        public Integer combine(Integer x, Integer y) {
            return x-y;
        }
    }
    static class BigDecimalAdder implements Combiner<BigDecimal>{

        @Override
        public BigDecimal combine(BigDecimal x, BigDecimal y) {
            return x.add(y);
        }
    }
    static class AtomicLongAdder implements Combiner<AtomicLong>{

        @Override
        public AtomicLong combine(AtomicLong x, AtomicLong y) {
            return new AtomicLong(x.addAndGet(y.get()));
        }
    }
    static class BigDecimalUlp implements UnaryFunction<BigDecimal,BigDecimal>{

        @Override
        public BigDecimal function(BigDecimal x) {
            return x.ulp();
        }
    }
    static class GreaterThan<T extends Comparable<T>>implements UnaryPredicate<T>{

        private T bound1;
        public GreaterThan(T bound){
            this.bound1=bound;
        }
        @Override
        public boolean test(T x) {
            return x.compareTo(bound1)>0;
        }
    }
    static class MultiplyingIntegerCollector implements Collector<Integer>{
        private Integer val=1;
        @Override
        public Integer function(Integer x) {
            val *=x;
            return val;
        }

        @Override
        public Integer result() {
            return val;
        }
    }

    public static void main(String[] args) {
        List<Integer> li= Arrays.asList(1,2,3,4,5,6,7);
        Integer result=reduce(li,new IntegerAdder());
        System.out.println(result);
        result=reduce(li,new IntegerSubtracter());
        System.out.println(result);
    }


}

